package mips.instructions.cop0;

import mips.instructions.Instruction;

/**
 * <code>TLBR</code> instruction<br/>
 * Read Indexed TLB Entry</br>
 * @author jnmartin84@gmail.com
 */
public class TLBR extends Instruction {

	private static final String INSTRUCTION_NAME = "TLBR";
	private static final TLBR INSTANCE = new TLBR();

	private TLBR(){}

	public static final TLBR getInstance() {
		return INSTANCE;
	}

	/**
	 * <b>Format:</b><br/>
	 * TLBR<br/><br/>
	 * <b>Description:</b><br/>
	 * The G bit (which controls ASID matching) read from the TLB is written<br/>
	 * into both of the EntryLo0 and EntryLo1 registers.<br/><br/>
	 * The EntryHi and EntryLo registers are loaded with the contents of the TLB<br/>
	 * entry pointed at by the contents of the TLB Index register. The operation<br/>
	 * is invalid (and the results are unspecified) if the contents of the TLB Index<br/>
	 * register are greater than the number of TLB entries in the processor.<br/><br/>
	 * <b>Operation:</b><br/>
	 * T: PageMask &larr; TLB[Index<sub>5...0</sub>]<sub>127...96</sub><br/>
	 * EntryHi &larr; TLB[Index<sub>5...0</sub>]<sub>95...64</sub> and not TLB[Index<sub>5...0</sub>]<sub>127...96</sub><br/>
	 * EntryLo1 &larr; TLB[Index<sub>5...0</sub>]<sub>63...32</sub><br/>
	 * EntryLo0 &larr; TLB[Index<sub>5...0</sub>]<sub>31...0</sub>
	 */
	@Override
	public final void execute(final int instruction) {

		// Index == 0
		// PageMask == 5
		// EntryHi == 10
		// EntryLo1 == 3
		// EntryLo0 == 2
		
		mips.COP0.TLB_Entry indexTlb = mips.COP0.JOINT_TLB[(int) (mips.COP0.CONTROL[0] & 0x0000001F)];

		mips.COP0.CONTROL[5] = indexTlb.entry[0];
		mips.COP0.CONTROL[10] = indexTlb.entry[1] & ~indexTlb.entry[0];
		mips.COP0.CONTROL[3] = indexTlb.entry[2];
		mips.COP0.CONTROL[2] = indexTlb.entry[3];
		
		mips.R4300i.PC = mips.R4300i.nPC;
		mips.R4300i.nPC = mips.R4300i.PC + 4;
	}

 	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String emit(final int instruction) {
		return	"		mips.COP0.TLB_Entry indexTlb = mips.COP0.JOINT_TLB[mips.COP0.CONTROL[0] & 0x0000001F];\n" + 
				"		\n" + 
				"		mips.COP0.CONTROL[5] = indexTlb.entry[0];\n" +
				"		mips.COP0.CONTROL[10] = indexTlb.entry[1] & ~indexTlb.entry[0];\n" + 
				"		mips.COP0.CONTROL[3] = indexTlb.entry[2];\n" + 
				"		mips.COP0.CONTROL[2] = indexTlb.entry[3];\n" + 
				"		\n" + 
				"		mips.R4300i.PC = mips.R4300i.nPC;\n" + 
				"		mips.R4300i.nPC = mips.R4300i.PC + 4;\n";
	}
	
 	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String getName(final int instruction) {
		return getName();
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String getName() {
		return INSTRUCTION_NAME;
	}
}